#include "common.h"
#include "sdcard.h"
#include <sys/mman.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <cstring>

#define Assert(cond, ...) \
  do { \
    if (!(cond)) { \
      fflush(stdout); \
      fprintf(stderr, "\33[1;31m"); \
      fprintf(stderr, __VA_ARGS__); \
      fprintf(stderr, "\33[0m\n"); \
      assert(cond); \
    } \
  } while (0)

#define SD_BLOCK_SIZE (1024)
static uint8_t *sd;

extern "C" {

uint8_t sd_read(uint32_t block_addr,uint32_t block_index) {
  // if (!data) return;
  // Assert(in_sd(addr), "SDcard address 0x%x out of bound", addr);
  return sd[block_addr*512 + block_index];
}

void sd_write(uint32_t block_addr , uint32_t block_index , uint8_t data){
    sd[block_addr*512 + block_index] = data;
}

// void init_sd(const char *img) {
//   FILE *sdfp = fopen(img, "rb");
//   Assert(sdfp, "Can not open '%s'", img);
  
//   fseek(sdfp, 0, SEEK_END);
//   uint64_t size = ftell(sdfp);
//   fseek(sdfp, 0, SEEK_SET);
//   assert(fread(sd, size, 1, sdfp) == 1);
//   fclose(sdfp);
// }

void init_sd(const char *img) {
  assert(img != NULL);
  // initialize memory using Linux mmap
  eprintf("The SD  image is %s\n" ANSI_COLOR_RESET, img);
  sd = (uint8_t *)mmap(NULL, SD_BLOCK_SIZE * 512, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
  if (sd == (uint8_t *)MAP_FAILED) {
    printf("Cound not mmap 0x%lx bytes\n", SD_BLOCK_SIZE * 512);
    assert(0);
  }
  FILE *sdfp = fopen(img, "rb");
  if (sdfp == NULL) {
    printf("Can not open '%s'\n", img);
    assert(0);
  }

  fseek(sdfp, 0, SEEK_END);
  int img_size = ftell(sdfp);
  if (img_size > SD_BLOCK_SIZE * 512) {
    img_size = SD_BLOCK_SIZE * 512;
  }

  fseek(sdfp, 0, SEEK_SET);
  int ret = fread(sd, img_size, 1, sdfp);

  assert(ret == 1);
  fclose(sdfp);
}
}
